Pairs

Row

Daily Active Users

Daily Trades

Row

Daily Trades Per User

Daily Trading Volume

Data

---
title: "Karura Swap Performance"
output:
  flexdashboard::flex_dashboard:
    theme: 
      version: 4
      bootswatch: minty
    orientation: rows
    vertical_layout: scroll
    social: menu
    source_code: embed
runtime: shiny
---

```{r global, include=FALSE}

library(flexdashboard)
library(DT)
library(shiny)

# Helper function to download data
create_dt <- function(x){
  DT::datatable(x,
                extensions = 'Buttons',
                options = list(dom = 'Blfrtip',
                               buttons = c('copy', 'csv', 'excel'),
                               lengthMenu = list(c(10, 50, -1),
                                                 c(10, 50, "All"))))
}

# helper function to color the bars in the charts (green, yellow, & red)
getColor <- function(status) {
  ifelse(status >= 1, "#34FF33", ifelse(status >= .5, "#FFC300", "#FF5733"))
}

# remotes::install_github("ropensci/ghql") # if package is not already installed
library(jsonlite)
library(data.table)
library("ghql")
x <- GraphqlClient$new()

endpoint <- "https://api.polkawallet.io/acala-subql"
window <- 15 # days to read in (latest day plus 7 day average)

# make a client
cli <- GraphqlClient$new(
  url = endpoint,
  headers = list("Accept-Encoding: gzip, deflate, br",
                 "Content-Type: application/json",
                 "Accept: application/json",
                 "Connection: keep-alive",
                 "DNT: 1",
                 "Origin: https://api.polkawallet.io")
)


mindate <- today(tzone = 'UTC') - window

### create a query class first
qry <- Query$new()
qry$query('dexActions', '{
  query {
    dexActions(filter: {timestamp: {greaterThanOrEqualTo: "' %+% mindate %+% '"}}) {
      nodes {
        timestamp
        id
        nodeId
        accountId
        type
        token0Id
        token1Id
        token0Amount
        token1Amount
        volumeUSD
        extrinsicId
        data
      }
    }
  }
}')
result <- cli$exec(qry$queries$dexActions) %>%
  fromJSON(flatten=TRUE)
res <- as.data.table(result$data$query$dexActions$nodes)

# Make sure we have 8 full days of data (compare latest day to prior 7 days)
maxdate <- mindate + days(window)
res <- res[timestamp <= maxdate]

res[, data := NULL]
res[, date := as.Date(timestamp)]
setorder(res, timestamp)

# Create pairs
res[, pair := paste0(res$token0Id, ":", res$token1Id)]
# Normalize pairs
res[pair == "KSM:KAR",  pair := "KAR:KSM"]
res[pair == "KSM:LKSM", pair := "LKSM:KSM"]
res[pair == "KSM:KUSD", pair := "KUSD:KSM"]
res[pair == "LKSM:KAR", pair := "KAR:LKSM"]
res[pair == "LKSM:KUSD",pair := "KUSD:LKSM"]
res[pair == "LKSM:BNC", pair := "BNC:LKSM"]
res[pair == "BNC:KAR",  pair := "KAR:BNC"]
res[pair == "BNC:LKSM", pair := "LKSM:BNC"]
res[pair == "BNC:KUSD", pair := "KUSD:BNC"]
res[pair == "KAR:KUSD", pair := "KUSD:KAR"]
res[pair == "BNC:KSM",  pair := "KSM:BNC"]

pairs <- rbind(res[type == 'swap', .N, by = pair], data.table(pair="ALL", N = res[, .N]))[order(N, decreasing = TRUE)] %>% 
  setnames(c("Pair", "Observations"))

res0 <<- res

```


# Inputs {.sidebar}

```{r}

# res0 <- fread("~/res.csv")

selectInput("pair", 
            label = "Select Trading Pair",
            choices = c("ALL", sort(unique(res0$pair))), 
            selected = 1)

  
renderTable(pairs)

selectInput("xdays", 
            label = "Comparison Window (days)",
            choices = 5:14, 
            selected = 7)

xdays <- reactive({input$xdays})

res <- reactive({
  
  # max(res0$date) - 7
  mywindow <- as.numeric(xdays()) # mywindow <- 7
  mypair <- input$pair # mypair = "KAR:BNC"
  if (input$pair == "ALL") return(res0[date >= max(res0$date) - mywindow])
  res0[pair == mypair & date >= max(res0$date) - mywindow]

})

renderText({"Start Date: " %+% min(res()$timestamp)})
renderText({"End Date: " %+% max(res()$timestamp)})

```

# Pairs {.tabset}
Row
----

### Daily Active Users

```{r}
renderPlot({

  activeUsers <- res()[!duplicated(accountId), .N, by = date] %>%
    setnames(c("Date","Active Users"))

  activeUsersAvg <- mean(head(activeUsers$`Active Users`, nrow(activeUsers) - 1))
  activeUsersStatus <- round(tail(activeUsers$`Active Users`, 1) / activeUsersAvg, 2)

  if (activeUsersStatus < 1) {
    txt1 <- " down " %+% as.character((activeUsersStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  } else {
    txt1 <- " up " %+% as.character((activeUsersStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  }
  
  p <- barplot(height = activeUsers$`Active Users`, names = activeUsers$Date,
          col=getColor(activeUsersStatus),
          ylab="",
          main = "Active Users" %+% txt1,
          las=2) +
        abline(h = activeUsersAvg)
  p

})
```

### Daily Trades

```{r}
renderPlot({

  trades <- res()[type == 'swap', .N, by = date] %>%
    setnames(c("Date","Trades"))
  
  tradesAvg <- mean(head(trades$`Trades`, nrow(trades) - 1))
  tradesStatus <- round(tail(trades$`Trades`, 1) / tradesAvg, 2)

  if (tradesStatus < 1) {
    txt2 <- " down " %+% as.character((tradesStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  } else {
    txt2 <- " up " %+% as.character((tradesStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  }

  p <- barplot(height = trades$`Trades`, names = trades$Date,
          col=getColor(tradesStatus),
          ylab="",
          main = "Trades" %+% txt2,
          las=2) +
        abline(h = tradesAvg)
  p

})

```

Row 
----

### Daily Trades Per User

```{r}
renderPlot({

  activeUsers <- res()[!duplicated(accountId), .N, by = date] %>%
    setnames(c("Date","Active Users"))
  
  trades <- res()[type == 'swap', .N, by = date] %>%
    setnames(c("Date","Trades"))

  avgTrade <- merge(trades, activeUsers, by = 'Date')
  avgTrade[, `Trades per user` := round(Trades / `Active Users`, 2)]
  
  avgTradeAvg <- mean(head(avgTrade$`Trades per user`, nrow(trades) - 1))
  avgTradeStatus <- round(tail(avgTrade$`Trades per user`, 1) / avgTradeAvg, 2)

  if (avgTradeStatus < 1) {
    txt3 <- " down " %+% as.character((avgTradeStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  } else {
    txt3 <- " up " %+% as.character((avgTradeStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  }

  p <- barplot(height = avgTrade$`Trades per user`, names = avgTrade$Date,
          col=getColor(avgTradeStatus),
          ylab="",
          main = "Trades Per User" %+% txt3,
          las=2) +
        abline(h = avgTradeAvg)
  p

})

```

### Daily Trading Volume

```{r}
renderPlot({

  tradeVolume <- res()[type == 'swap', sum(as.numeric(volumeUSD) / 1e12 / 1e6), by = date] %>%
    setnames(c("Date","Trading Volume"))
  
  tradeVolumeAvg <- mean(head(tradeVolume$`Trading Volume`, nrow(tradeVolume) - 1))
  tradeVolumeStatus <- round(tail(tradeVolume$`Trading Volume`, 1) / tradeVolumeAvg, 2)

  if (tradeVolumeStatus < 1) {
    txt4 <- " down " %+% as.character((tradeVolumeStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  } else {
    txt4 <- " up " %+% as.character((tradeVolumeStatus-1)*100) %+% "% vs. " %+% xdays() %+% "D Avg"
  }
  
  p <- barplot(height = tradeVolume$`Trading Volume`, names = tradeVolume$Date,
          col=getColor(tradeVolumeStatus),
          ylab="",
          main = "Trading Volume" %+% txt4,
          las=2) +
        abline(h = tradeVolumeAvg)
  p

})

```

# Data

```{r}
DT::renderDataTable({create_dt(res())})
```